﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace CivLib.CivNum
{
  class StageSeries
  {
    double[] m_stage;
    double[] m_storage;
    double[] m_discharge;
    double m_totalDepth;
    int m_numEntry;
    double m_stageInc;

    /// <summary>
    /// Array of the stage points
    /// </summary>
    public double[] Stage
    {
      get { return m_stage; }
    }
    /// <summary>
    /// Array of the storage points
    /// </summary>
    public double[] Storage
    {
      get { return m_storage; }
      set { m_storage = value; }
    }
    /// <summary>
    /// Array of the discharge points
    /// </summary>
    public double[] Discharge
    {
      get { return m_discharge; }
      set { m_discharge = value; }
    }
    /// <summary>
    /// Number of entries in the series
    /// </summary>
    public int Count
    {
      get { return m_stage.Length; }
    }
    /// <summary>
    /// The uniform depth incrament
    /// </summary>
    public double StageInc
    {
      get { return m_stageInc; }
    }

    /// <summary>
    /// Constructor for StageSeries with a given number of entries 
    /// evenly spaced over a total depth.
    /// </summary>
    /// <param name="a_numberOfEntries">number of points in the series</param>
    /// <param name="a_totalDepth">total depth to span</param>
    public StageSeries(int a_numberOfEntries, double a_totalDepth)
    {
      m_totalDepth = a_totalDepth;
      m_numEntry = a_numberOfEntries;
      m_stage = new double[m_numEntry];
      m_storage = new double[m_numEntry];
      m_discharge = new double[m_numEntry];
      SetNumSteps(m_numEntry);
    }

    /// <summary>
    /// Sets the number of steps in the series and spaces them
    /// evenly across the spanned depth.
    /// </summary>
    /// <param name="a_steps">number of steps</param>
    public void SetNumSteps(int a_steps)
    {
      m_numEntry = a_steps;
      m_stageInc = m_totalDepth / m_numEntry;
      Array.Resize(ref m_stage, m_numEntry);
      Array.Resize(ref m_storage, m_numEntry);
      Array.Resize(ref m_discharge, m_numEntry);
      for (int i = 0; i < m_stage.Length; i++)
      {
        m_stage[i] = i * m_stageInc;
      }
    }

    /// <summary>
    /// Interpolate a discharge from a given stage
    /// </summary>
    /// <param name="a_stage">stage to interpolate at</param>
    /// <returns>interpolated discharge or max if greater than stage and min if less than stage</returns>
    public double DischFrStage(double a_stage)
    {
      int binInd = Array.BinarySearch<double>(m_stage, a_stage);
      //if the index is less than zero then it is the bitwise compliment
      //of the next largest index
      if (binInd < 0)
      {
        binInd = ~binInd;
        if (binInd == 0)
          return m_discharge[0];
        if (binInd == m_stage.Length)
          return m_discharge[m_stage.Length - 1];
        CivPoint2D firstPoint = new CivPoint2D(m_stage[binInd - 1], m_discharge[binInd - 1]);
        CivPoint2D secondPoint = new CivPoint2D(m_stage[binInd], m_discharge[binInd]);
        return Interp.Linear(firstPoint, secondPoint, a_stage).y;
      }
      else
      {
        return m_discharge[binInd];
      }
    }

    public double StorFrStage(double a_stage)
    {
      int binInd = Array.BinarySearch<double>(m_stage, a_stage);
      //if the index is less than zero then it is the bitwise compliment
      //of the next largest index
      if (binInd < 0)
      {
        binInd = ~binInd;
        if (binInd == 0)
          return m_storage[0];
        if (binInd == m_stage.Length)
          return m_storage[m_stage.Length - 1];
        CivPoint2D firstPoint = new CivPoint2D(m_stage[binInd - 1], m_storage[binInd - 1]);
        CivPoint2D secondPoint = new CivPoint2D(m_stage[binInd], m_storage[binInd]);
        return Interp.Linear(firstPoint, secondPoint, a_stage).y;
      }
      else
      {
        return m_storage[binInd];
      }
    }

    public double StageFrStor(double a_storage)
    {
      int binInd = Array.BinarySearch<double>(m_storage, a_storage);
      //if the index is less than zero then it is the bitwise compliment
      //of the next largest index
      if (binInd < 0)
      {
        binInd = ~binInd;
        if (binInd == 0)
          return m_stage[0];
        if (binInd == m_storage.Length)
          return m_stage[m_storage.Length - 1];
        CivPoint2D firstPoint = new CivPoint2D(m_storage[binInd - 1], m_storage[binInd - 1]);
        CivPoint2D secondPoint = new CivPoint2D(m_storage[binInd], m_storage[binInd]);
        return Interp.Linear(firstPoint, secondPoint, a_storage).y;
      }
      else
      {
        return m_storage[binInd];
      }
    }

  }

}
